#pragma once
#include <iostream>
#include <unordered_map>
#include <vector>
#include <string>
#include "../mqcommon/Helper.hpp"
#include "../mqcommon/Log.hpp"
#include "../mqcommon/msg.pb.h"
using namespace std;
namespace mq
{
    class Consumer
    {
    public:
        using CallBackType = function<void(const string &, const BasicProperties *bp, const string &)>;
        using ConsumerPtr = shared_ptr<Consumer>;
        string _tag;
        string _qname;
        bool _auto_ack;
        CallBackType _callback;
        Consumer() {}
        Consumer(const string &tag, const string &qname, bool auto_ack, const CallBackType &callback)
            : _tag(tag), _qname(qname), _auto_ack(auto_ack), _callback(callback)
        {
        }
    };
    class QueueConsumer
    {
    public:
        using QueueConsumerPtr = shared_ptr<QueueConsumer>;
        QueueConsumer(const string &qname)
            : _qname(qname), _idx(0)
        {
        }
        // 新建消费者并添加到管理队列中
        Consumer::ConsumerPtr create(const string &tag, const string &name,
                                     bool ack_flag, const Consumer::CallBackType &cb)
        {
            {
                unique_lock<mutex> lock(_mutex);
                for (auto &it : _consumers)
                {
                    if (it->_tag == tag)
                        return Consumer::ConsumerPtr();
                }
            }
            Consumer::ConsumerPtr cp = make_shared<Consumer>(tag, name, ack_flag, cb);
            _consumers.push_back(cp);
            return cp;
        }
        // 从管理队列中删除消费者
        void remove(const string &tag)
        {
            unique_lock<mutex> lock(_mutex);
            for (auto it = _consumers.begin(); it != _consumers.end(); ++it)
            {
                if ((*it)->_tag == tag)
                {
                    _consumers.erase(it);
                    return;
                }
            }
        }
        // 根据轮转选择一个消费者
        Consumer::ConsumerPtr choose()
        {
            unique_lock<mutex> lock(_mutex);
            if (_consumers.size() == 0)
                return Consumer::ConsumerPtr();
            size_t idx = (_idx) % _consumers.size();
            _idx = (_idx + 1) % _consumers.size();
            return _consumers[idx];
        }
        // 判断消费者管理队列是否为空
        bool empty()
        {
            unique_lock<mutex> lock(_mutex);
            return _consumers.size() == 0;
        }
        // 判断消费者管理队列中是否存在指定消费者
        bool exists(const string &tag)
        {
            unique_lock<mutex> lock(_mutex);
            for (auto &it : _consumers)
            {
                if (it->_tag == tag)
                    return true;
            }
            return false;
        }
        // 清空消费者管理队列
        void clear()
        {
            unique_lock<mutex> lock(_mutex);
            _consumers.clear();
        }

    private:
        mutex _mutex;
        string _qname;
        size_t _idx;
        vector<Consumer::ConsumerPtr> _consumers; // 消费者管理队列
    };
    class ConsumerManager
    {
    public:
        using ConsumerManagerPtr = shared_ptr<ConsumerManager>;
        ConsumerManager() {}
        // 初始化（新建）消费者管理队列
        void initQueueConsumer(const string &qname)
        {
            unique_lock<mutex> lock(_mutex);
            auto it = _consumers.find(qname);
            if (it != _consumers.end())
                return;
            QueueConsumer::QueueConsumerPtr qcp = make_shared<QueueConsumer>(qname);
            _consumers.insert(make_pair(qname, qcp));
        }
        // 销毁消费者管理队列
        void destroyQueueConsumer(const string &qname)
        {
            unique_lock<mutex> lock(_mutex);
            auto it = _consumers.find(qname);
            if (it == _consumers.end())
                return;
            _consumers.erase(qname);
        }
        // 创建消费者并插入指定消费者管理队列中
        Consumer::ConsumerPtr create(const string &tag, const string &qname, bool ack_flag,
                                     const Consumer::CallBackType &cb)
        {
            QueueConsumer::QueueConsumerPtr qcp;
            {
                unique_lock<mutex> lock(_mutex);
                auto it = _consumers.find(qname);
                if (it == _consumers.end())
                {
                    DLOG("找不到目标队列操作句柄: %s", qname.c_str());
                    return Consumer::ConsumerPtr();
                }
                qcp = it->second;
            }
            return qcp->create(tag, qname, ack_flag, cb);
        }
        // 从管理队列中移除指定消费者
        void remove(const string &tag, const string &qname)
        {
            QueueConsumer::QueueConsumerPtr qcp;
            {
                unique_lock<mutex> lock(_mutex);
                auto it = _consumers.find(qname);
                if (it == _consumers.end())
                {
                    DLOG("找不到目标队列操作句柄: %s", qname.c_str());
                    return;
                }
                qcp = it->second;
            }
            qcp->remove(tag);
        }
        // 选择一个消费者
        Consumer::ConsumerPtr choose(const string &qname)
        {
            QueueConsumer::QueueConsumerPtr qcp;
            {
                unique_lock<mutex> lock(_mutex);
                auto it = _consumers.find(qname);
                if (it == _consumers.end())
                {
                    DLOG("找不到目标队列操作句柄: %s", qname.c_str());
                    return Consumer::ConsumerPtr();
                }
                qcp = it->second;
            }
            return qcp->choose();
        }
        // 判断指定消费者管理队列是否为空
        bool empty(const string &qname)
        {
            QueueConsumer::QueueConsumerPtr qcp;
            {
                unique_lock<mutex> lock(_mutex);
                auto it = _consumers.find(qname);
                if (it == _consumers.end())
                {
                    DLOG("找不到目标队列操作句柄: %s", qname.c_str());
                    return false;
                }
                qcp = it->second;
            }
            return qcp->empty();
        }
        // 判断指定消费者管理队列中指定消费者是否存在
        bool exists(const string &tag, const string &qname)
        {
            QueueConsumer::QueueConsumerPtr qcp;
            {
                unique_lock<mutex> lock(_mutex);
                auto it = _consumers.find(qname);
                if (it == _consumers.end())
                {
                    DLOG("找不到目标队列操作句柄: %s", qname.c_str());
                    return false;
                }
                qcp = it->second;
            }
            return qcp->exists(tag);
        }
        // 清空所有消费者管理队列
        void clear()
        {
            unique_lock<mutex> lock(_mutex);
            for (auto &qcp : _consumers)
                qcp.second->clear();
        }

    private:
        mutex _mutex;
        unordered_map<string, QueueConsumer::QueueConsumerPtr> _consumers;
    };
}